#include "CameraLookat.h"

CameraLookat::CameraLookat()
	:Camera3D()
{
	LOGIDBG("Init LookAtCamera\n");
	Projection.SetIdentity().SetPerspective(FOV, ASPECTRATIO, NEAREST, FATHEST);
}

CameraLookat::~CameraLookat()
{
	LOGIDBG("Destroy LookAtCamera\n");
}

Matrix CameraLookat::CalculateWorld()
{
	Vector3 zaxis = (Position - Target).Normalize();
	Vector3 xaxis = (Up.Cross(zaxis)).Normalize();
	Vector3 yaxis = (zaxis.Cross(xaxis)).Normalize();

	Matrix rot = Matrix().SetIdentity();
	rot.m[0][0] = xaxis.x;
	rot.m[0][1] = xaxis.y;
	rot.m[0][2] = xaxis.z;

	rot.m[1][0] = yaxis.x;
	rot.m[1][1] = yaxis.y;
	rot.m[1][2] = yaxis.z;

	rot.m[2][0] = zaxis.x;
	rot.m[2][1] = zaxis.y;
	rot.m[2][2] = zaxis.z;

	Matrix trans = Matrix().SetIdentity();
	trans.m[3][0] = Position.x; trans.m[3][1] = Position.y; trans.m[3][2] = Position.z;

	m_world = rot*trans;
	return m_world;
}

Matrix CameraLookat::CalculateView()
{
	Vector3 zaxis = (Position - Target).Normalize();
	Vector3 xaxis = (Up.Cross(zaxis)).Normalize();
	Vector3 yaxis = (zaxis.Cross(xaxis)).Normalize();

	Matrix rotT = Matrix().SetIdentity();
	rotT.m[0][0] = xaxis.x;
	rotT.m[0][1] = yaxis.x;
	rotT.m[0][2] = zaxis.x;

	rotT.m[1][0] = xaxis.y;
	rotT.m[1][1] = yaxis.y;
	rotT.m[1][2] = zaxis.y;

	rotT.m[2][0] = xaxis.z;
	rotT.m[2][1] = yaxis.z;
	rotT.m[2][2] = zaxis.z;

	Matrix transT = Matrix().SetIdentity();
	transT.m[3][0] = -Position.x; transT.m[3][1] = -Position.y; transT.m[3][2] = -Position.z;

	View = transT*rotT;
	return View;
}

void CameraLookat::MoveForward(FWfloat offset)
{
	Vector3 zdelta = -(Position - Target).Normalize()*offset;
	Position += zdelta;
	Target += zdelta;
}

void CameraLookat::MoveBackward(FWfloat offset)
{
	Vector3 zdelta = (Position - Target).Normalize()*offset;
	Position += zdelta;
	Target += zdelta;
}

void CameraLookat::MoveLeft(FWfloat offset)
{
	Vector3 zdelta = -(Position - Target).Normalize();
	Vector3 xdelta = (Up.Cross(zdelta).Normalize())*offset;
	Position += xdelta;
	Target += xdelta;
}

void CameraLookat::MoveRight(FWfloat offset)
{
	Vector3 zdelta = -(Position - Target).Normalize();
	Vector3 xdelta = (-Up.Cross(zdelta).Normalize())*offset;
	Position += xdelta;
	Target += xdelta;
}

void CameraLookat::RotateUp(FWfloat angle)
{
	Vector4 localTarget = Vector4(0.0f, 0.0f, -(Position - Target).Length(), 1.0f);
	Vector4 localNewTarget = localTarget*Matrix().SetIdentity().SetRotationX(angle);
	Vector4 worldNewTarget = localNewTarget*CalculateWorld();
	Target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
}

void CameraLookat::RotateDown(FWfloat angle)
{
	Vector4 localTarget = Vector4(0.0f, 0.0f, -(Position - Target).Length(), 1);
	Vector4 localNewTarget = localTarget*Matrix().SetIdentity().SetRotationX(-angle);
	Vector4 worldNewTarget = localNewTarget*CalculateWorld();
	Target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
}

void CameraLookat::RotateLeft(FWfloat angle)
{
	Vector4 localTarget = Vector4(0.0f, 0.0f, -(Position - Target).Length(), 1);
	Vector4 localNewTarget = localTarget*Matrix().SetIdentity().SetRotationY(angle);
	Vector4 worldNewTarget = localNewTarget*CalculateWorld();
	Target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
}

void CameraLookat::RotateRight(FWfloat angle)
{
	Vector4 localTarget = Vector4(0.0f, 0.0f, -(Position - Target).Length(), 1);
	Vector4 localNewTarget = localTarget*Matrix().SetIdentity().SetRotationY(-angle);
	Vector4 worldNewTarget = localNewTarget*CalculateWorld();
	Target = Vector3(worldNewTarget.x, worldNewTarget.y, worldNewTarget.z);
}
